package com.lqk.nio.selector;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class NIOServer {
    public static void main(String[] args) throws IOException {

        // 创建ServerSocketChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 得到一个selector对象
        Selector selector = Selector.open();
        // 绑定端口6666，在服务器端监听
        serverSocketChannel.socket().bind(new InetSocketAddress(6666));
        // 设置为非阻塞状态
        serverSocketChannel.configureBlocking(false);
        // 把 serverSocketChannel 注册到 selector 关心事件为 OP_ACCEPT：连接事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        // 循环监听客户端连接
        while (true){
            // 阻塞等待1秒
            if (selector.select(1000)==0){
                System.out.println("服务等待了1秒，无连接");
                continue;
            }
            // 如果返回>0, 获取到相关的selectionKey集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            // 遍历Set<SelectionKey>，使用迭代器遍历
            Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
            while (keyIterator.hasNext()){
                // 获取到SelectionKey
                SelectionKey selectionKey = keyIterator.next();
                // 根据selectionKey对应的通道发生的事件做相应的处理
                if (selectionKey.isAcceptable()){//有新的客户端连接我
                    // 为该客户端生成一个SocketChannel
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    System.out.println("客户端连接成功，生成了一个socketChannel："+socketChannel.hashCode());
                    // 切换非阻塞模式
                    socketChannel.configureBlocking(false);
                    // 将socketChannel注册到selector, 关注事件：OP_READ，同时给该channel关联一个Buffer
                    socketChannel.register(selector,SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }else if (selectionKey.isReadable()){// 发生OP_READ
                   // 通过key反向获取对应的channel
                   SocketChannel socketChannel =(SocketChannel) selectionKey.channel();
                   // 获取到该channel关联的buffer
                   ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
                   byteBuffer.clear();
                   socketChannel.read(byteBuffer);
                   byteBuffer.flip();// 模式转换
                   System.out.println("from客户端："+new String(byteBuffer.array()));
                }
                // 手动从集合中移动当前的selectionKey，防止重复操作
                keyIterator.remove();
            }

        }

    }
}
